1   /*
2    * Copyright (C) 2012 The Guava Authors
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package com.google.common.collect;
17  
18  import static com.google.common.base.Preconditions.checkArgument;
19  
20  import com.google.common.annotations.GwtCompatible;
21  
22  import java.io.Serializable;
23  import java.util.EnumMap;
24  import java.util.Iterator;
25  
26  import javax.annotation.Nullable;
27  
28  /**
29   * Implementation of {@link ImmutableMap} backed by a non-empty {@link
30   * java.util.EnumMap}.
31   *
32   * @author Louis Wasserman
33   */
34  @GwtCompatible(serializable = true, emulated = true)
35  @SuppressWarnings("serial") // we're overriding default serialization
36  final class ImmutableEnumMap<K extends Enum<K>, V> extends ImmutableMap<K, V> {
37    static <K extends Enum<K>, V> ImmutableMap<K, V> asImmutable(EnumMap<K, V> map) {
38      switch (map.size()) {
39        case 0:
40          return ImmutableMap.of();
41        case 1: {
42          Entry<K, V> entry = Iterables.getOnlyElement(map.entrySet());
43          return ImmutableMap.of(entry.getKey(), entry.getValue());
44        }
45        default:
46          return new ImmutableEnumMap<K, V>(map);
47      }
48    }
49  
50    private transient final EnumMap<K, V> delegate;
51  
52    private ImmutableEnumMap(EnumMap<K, V> delegate) {
53      this.delegate = delegate;
54      checkArgument(!delegate.isEmpty());
55    }
56  
57    @Override
58    ImmutableSet<K> createKeySet() {
59      return new ImmutableSet<K>() {
60  
61        @Override
62        public boolean contains(Object object) {
63          return delegate.containsKey(object);
64        }
65  
66        @Override
67        public int size() {
68          return ImmutableEnumMap.this.size();
69        }
70  
71        @Override
72        public UnmodifiableIterator<K> iterator() {
73          return Iterators.unmodifiableIterator(delegate.keySet().iterator());
74        }
75  
76        @Override
77        boolean isPartialView() {
78          return true;
79        }
80      };
81    }
82  
83    @Override
84    public int size() {
85      return delegate.size();
86    }
87  
88    @Override
89    public boolean containsKey(@Nullable Object key) {
90      return delegate.containsKey(key);
91    }
92  
93    @Override
94    public V get(Object key) {
95      return delegate.get(key);
96    }
97  
98    @Override
99    ImmutableSet<Entry<K, V>> createEntrySet() {
100     return new ImmutableMapEntrySet<K, V>() {
101 
102       @Override
103       ImmutableMap<K, V> map() {
104         return ImmutableEnumMap.this;
105       }
106 
107       @Override
108       public UnmodifiableIterator<Entry<K, V>> iterator() {
109         return new UnmodifiableIterator<Entry<K, V>>() {
110           private final Iterator<Entry<K, V>> backingIterator = delegate.entrySet().iterator();
111 
112           @Override
113           public boolean hasNext() {
114             return backingIterator.hasNext();
115           }
116 
117           @Override
118           public Entry<K, V> next() {
119             Entry<K, V> entry = backingIterator.next();
120             return Maps.immutableEntry(entry.getKey(), entry.getValue());
121           }
122         };
123       }
124     };
125   }
126 
127   @Override
128   boolean isPartialView() {
129     return false;
130   }
131 
132   // All callers of the constructor are restricted to <K extends Enum<K>>.
133   @Override Object writeReplace() {
134     return new EnumSerializedForm<K, V>(delegate);
135   }
136 
137   /*
138    * This class is used to serialize ImmutableEnumSet instances.
139    */
140   private static class EnumSerializedForm<K extends Enum<K>, V>
141       implements Serializable {
142     final EnumMap<K, V> delegate;
143     EnumSerializedForm(EnumMap<K, V> delegate) {
144       this.delegate = delegate;
145     }
146     Object readResolve() {
147       return new ImmutableEnumMap<K, V>(delegate);
148     }
149     private static final long serialVersionUID = 0;
150   }
151 }